package com.kungfuhacking.wristbandpro.chat.activity;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.support.v4.view.ViewPager;
import android.text.Editable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.alibaba.fastjson.JSONObject;
import com.kungfuhacking.wristbandpro.R;
import com.kungfuhacking.wristbandpro.audio.MediaRecordManager;
import com.kungfuhacking.wristbandpro.audio.UPlayer;
import com.kungfuhacking.wristbandpro.base.bean.RequestBean;
import com.kungfuhacking.wristbandpro.base.bean.UploadBean;
import com.kungfuhacking.wristbandpro.base.view.BaseActivity;
import com.kungfuhacking.wristbandpro.base.view.HomeActivity;
import com.kungfuhacking.wristbandpro.chat.presenter.ChatAdapter;
import com.kungfuhacking.wristbandpro.chat.presenter.EmoAdapter;
import com.kungfuhacking.wristbandpro.chat.presenter.PhotoAdapter;
import com.kungfuhacking.wristbandpro.custom.TitleBarView;
import com.kungfuhacking.wristbandpro.database.DatabaseManager;
import com.kungfuhacking.wristbandpro.login.activity.LoginActivity;
import com.kungfuhacking.wristbandpro.mqtt.MqttConstant;
import com.kungfuhacking.wristbandpro.mqtt.MqttManager;
import com.kungfuhacking.wristbandpro.mqtt.bean.MessageBean;
import com.kungfuhacking.wristbandpro.mqtt.bean.VideoBean;
import com.kungfuhacking.wristbandpro.net.BaseNoTObserver;
import com.kungfuhacking.wristbandpro.net.RetrofitHttpUtil;
import com.kungfuhacking.wristbandpro.photoView.PhotoViewAttacher;
import com.kungfuhacking.wristbandpro.utils.CommonUtils;
import com.kungfuhacking.wristbandpro.utils.Constant;
import com.kungfuhacking.wristbandpro.utils.LogUtil;
import com.kungfuhacking.wristbandpro.widget.ChatView;
import com.kungfuhacking.wristbandpro.widget.MyTextView;
import com.kungfuhacking.wristbandpro.widget.RecorderTextView;
import com.qiniu.android.http.ResponseInfo;
import com.qiniu.android.storage.UpCompletionHandler;
import com.qiniu.android.storage.UploadManager;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import io.reactivex.disposables.Disposable;


/**
 * 单聊页面
 * Created by Aaron on 16/1/14.
 */
public class ChatActivity extends BaseActivity implements View.OnClickListener {

    private static final int QUERYHISTORY = 0x23;
    private static final int TAKE_PHOTO_CODE = 0x25;
    private static final int CHOOSE_PHOTO_CHAT_CODE = 0x26;
    private RecorderTextView tv_rcd;
    private EditText et_sendmessage;
    //    private MessageBean mb;
    private boolean isTalk;//是否是语音状态
    private ChatAdapter chatAdapter;
    private List<MessageBean> lists;
    private ListView lv_contents;
    private Dialog dialog;
    private ImageView iv_voice;
    private TextView tv_mind;
    private boolean isShowEmo;
    private static final int MDEIAVOICE = 0x66;
    //    private static final int PROGRESSMISS = 0x67;
    private ViewPager vp_emotion;
    private RelativeLayout ll_root;
    private ImageView iv_audio;
    private ImageView iv_emotion;
    private ImageView iv_add;
    private int startIndex;
    private GridView gv_photo;
    private boolean isShowPhoto;//是否显示选择图片布局
    private File takePhotoFile;
    private MessageBean contact;
    //    private TextView tv_title;
    private Intent mIntent;
    private ImageView pv_pre;
    //    private MessageBean messageBean;
    private String showingPhotoUrl;//正在详情的图url
    //    public float startX = -1;
//    public float startY = -1;
    private Bitmap detailBitmap; //查看详情的bitmap
    private PhotoViewAttacher mAttacher;
    private boolean isShowingPicDetail;
    private RelativeLayout rl_pre;
    private long speakTime;//开始录音时间
    //    private int currentChatType;//当前聊天类型, 群聊 还是私聊
    private boolean send = true;
    private RelativeLayout rl_emo;
    private ImageView iv_emo_middle;
    private ImageView iv_emo_left;
    private ImageView iv_emo_right;
    private TextView tv_send;

    private String TAG = getClass().getSimpleName();
    private TitleBarView tbv;
    private ExecutorService executorService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        EventBus.getDefault().register(this);

        setContentView(R.layout.activity_chat);

        //contact 需要有 topic 字段, receiveName 字段, receivePic字段, chatType 单聊还是私聊
        if (bundle != null)
            contact = bundle.getParcelable("contact");

        if (contact == null) {
            finish();
            return;
        }

        initWidget();
        //创建一个固定线程数为3的线程池
        executorService = Executors.newFixedThreadPool(3);
        //查找最近的20条的聊天记录, 通过topic来查询
        executorService.execute(historyRunnable);

        if (sp.getBoolean(Constant.FIRST_RECORD, true)) {
            Log.d(TAG, "   =======   获取录音权限   =======   ");
            //只是为了提前获取录音权限用
            try {
                MediaRecordManager.getInstance().startRecordAndFile(this);
                MediaRecordManager.getInstance().stopRecordAndFile();
                MediaRecordManager.getInstance().deleteMediaRecord();
            } catch (Exception e) {
                e.printStackTrace();
            }

            sp.edit().putBoolean(Constant.FIRST_RECORD, false).apply();
        }

    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();

        executorService.execute(new Runnable() {
            @Override
            public void run() {
                //把改聊天的未读消息个数置为0
                DatabaseManager.getInstance().clearRedCount(ChatActivity.this, new String[]{"0", contact.channelId, sp.getString(MqttConstant.USERID, "")});
            }
        });

        //停止播放语音文件
        if (chatAdapter != null)
            chatAdapter.stopPlayVideo();

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        MqttConstant.currentContractTopic = "";//清除掉当前聊天的id

        if (executorService != null)
            executorService.shutdown();

//        if (scheduledExecutor != null)
//            scheduledExecutor.shutdown();

        EventBus.getDefault().unregister(this);

        //回收bitmap
        if (detailBitmap != null) {
            detailBitmap.recycle();
            detailBitmap = null;
        }
        currentShowTime = 0;

        //移除message
        mHandler.removeCallbacksAndMessages(null);

    }

    private long currentShowTime;

    /**
     * 查询历史聊天记录的runnable
     */
    private Runnable historyRunnable = new Runnable() {
        @Override
        public void run() {

            if (contact == null)
                return;

            List<MessageBean> historyByTopic = DatabaseManager.getInstance().queryChatHistory(ChatActivity.this, sp.getString(MqttConstant.USERID, ""), contact.channelId, startIndex);

            //遍历聊天记录，设置是否显示发送时间
            for (int i = 0; i < historyByTopic.size(); i++) {

                //判断是否显示时间
                if (currentShowTime == 0) {
                    historyByTopic.get(i).showTime = true;
                    currentShowTime = historyByTopic.get(i).sendDate;
                } else if ((currentShowTime - historyByTopic.get(i).sendDate) >= 3 * 60 * 1000) {
                    historyByTopic.get(i).showTime = true;
                    currentShowTime = historyByTopic.get(i).sendDate;
                } else {
                    historyByTopic.get(i).showTime = false;
                }

            }

            Collections.reverse(historyByTopic);

            Message msg = Message.obtain();
            msg.what = QUERYHISTORY;
            msg.obj = historyByTopic;
            mHandler.sendMessage(msg);

        }
    };

    private void initWidget() {

        lv_contents = (ListView) findViewById(R.id.lv_contents);
        iv_add = (ImageView) findViewById(R.id.iv_add);
        iv_emotion = (ImageView) findViewById(R.id.iv_emotion);
        et_sendmessage = (EditText) findViewById(R.id.et_sendmessage);
        iv_audio = (ImageView) findViewById(R.id.iv_audio);
        pv_pre = (ImageView) findViewById(R.id.pv_pre);
        TextView tv_save = (TextView) findViewById(R.id.tv_save);
        tv_rcd = (RecorderTextView) findViewById(R.id.tv_rcd);
        tbv = (TitleBarView) findViewById(R.id.tbv);
        LinearLayout ll_bottom_total = (LinearLayout) findViewById(R.id.ll_bottom_total);
        tv_send = (MyTextView) findViewById(R.id.tv_send);
        rl_emo = (RelativeLayout) findViewById(R.id.rl_emo);//表情布局
        iv_emo_middle = (ImageView) findViewById(R.id.iv_emo_middle);
        iv_emo_left = (ImageView) findViewById(R.id.iv_emo_left);
        iv_emo_right = (ImageView) findViewById(R.id.iv_emo_right);
        rl_pre = (RelativeLayout) findViewById(R.id.rl_pre);
        ll_root = (RelativeLayout) findViewById(R.id.ll_root);
        vp_emotion = (ViewPager) findViewById(R.id.vp_emotion);

        if (contact != null)
            tbv.setTitle(contact.receiveName);//设置聊天对象昵称

        if (contact != null && contact.channelId.startsWith(MqttConstant.START_S)) { //系统聊天, 不显示设置 和 底部聊天框
            tbv.setRightVisible(false);
            ll_bottom_total.setVisibility(View.GONE);
        }

        //设置
        tbv.setOnRightClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Bundle b = new Bundle();
//                if (contact != null && CommonUtils.isGroupChat(contact.channelId)) {//群聊
                b.putString("topic", contact.channelId);
                nextActivityWithBundle(ChatSetActivity.class, b);
//                } else {//私聊
//                    b.putParcelable("contact", contact);
//                    nextActivityWithBundle(ChatSetActivity.class, b);
//                }
            }
        });
        iv_audio.setOnClickListener(this);
        iv_emotion.setOnClickListener(this);
        iv_add.setOnClickListener(this);
        tv_send.setOnClickListener(this);

        tv_save.setOnClickListener(this);
        tbv.setOnLeftClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                nextActivity(HomeActivity.class);
            }
        });

        lists = new ArrayList<>();

        gv_photo = (GridView) findViewById(R.id.gv_photo);

        PhotoAdapter photoAdapter = new PhotoAdapter(this);

        gv_photo.setAdapter(photoAdapter);

        chatAdapter = new ChatAdapter(lists, this);
        lv_contents.setAdapter(chatAdapter);

        //设置监听
        setListener();

//        //是否显示设置按钮
//        if (MqttConstant.topicMap == null)
//            MqttConstant.topicMap = (Map<String, TopicBean>) JSON.parse(sp.getString(MqttConstant.TOPIC_MAP, ""));
//
//        if (MqttConstant.topicMap == null || !MqttConstant.topicMap.containsKey(contact.channelId))
//            tbv.setRightVisible(false);

    }

    private void setListener() {

        //发送信息
        et_sendmessage.setOnEditorActionListener(new TextView.OnEditorActionListener() {

            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                return (actionId == EditorInfo.IME_ACTION_SEND || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) && sendChatMessage();

            }
        });

        ll_root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {

//                LogUtil.e("tag", "键盘的高度 : " + (ll_root.getRootView().getHeight() - ll_root.getHeight()));
//                LogUtil.e("tag", "3 分 之 1 的高度 : " + (CommonUtils.getScreenSize(ChatActivity.this)[1] / 3));

                if (ll_root.getRootView().getHeight() - ll_root.getHeight() >= CommonUtils.getScreenSize(ChatActivity.this)[1] / 3) {
                    //软键盘显示了
                    lv_contents.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
                    lv_contents.setSelection(lv_contents.getCount());
                }
            }
        });

        //表情viewpager滑动的监听
        vp_emotion.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            }

            @Override
            public void onPageSelected(int position) {
                setPoint(position);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });

        et_sendmessage.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {

                if (TextUtils.isEmpty(s.toString())) {
                    iv_add.setVisibility(View.VISIBLE);
                    tv_send.setVisibility(View.GONE);
                } else {
                    iv_add.setVisibility(View.GONE);
                    tv_send.setVisibility(View.VISIBLE);
                }

            }
        });

    }

    private boolean sendChatMessage() {

        if (TextUtils.isEmpty(et_sendmessage.getText().toString().trim())) {
            showErr("不能发送空白消息");
            et_sendmessage.setText("");
            return true;
        }

        if (contact == null) {
            showErr("信息异常");
            return true;
        }

//        if (!CommonUtils.isFriendOrGroupNum(sp, ChatActivity.this, contact.channelId))//和对方不是好友,或者不是群成员,无法发送消息
//            return true;

        //获取到发送的mb
        MessageBean mb = getSendMessageBean(MqttConstant.MQTTMESSAGETEXT, et_sendmessage.getText().toString(), 0);

        sendMsg(mb);//发送聊天消息

        return true;
    }

    public void fush() {
        lv_contents.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_DISABLED);
        chatAdapter.notifyDataSetChanged();
    }

    private void setPoint(int position) {

        iv_emo_middle.setSelected(false);
        iv_emo_left.setSelected(false);
        iv_emo_right.setSelected(false);

        switch (position) {

            case 0:
                iv_emo_left.setSelected(true);
                break;
            case 1:
                iv_emo_middle.setSelected(true);
                break;
            case 2:
                iv_emo_right.setSelected(true);
                break;
        }

    }

    /**
     * 把图片保存至本地
     */
    private void savePic2Local() {

        if (!TextUtils.isEmpty(showingPhotoUrl)) {

            String cacheDir = Environment.getExternalStorageDirectory().getPath() + Constant.PHOTO_PATH;

            File photoFile = new File(cacheDir);
            //文件夹不存在就创建文件夹
            if (!photoFile.exists())
                photoFile.mkdirs();

            if (detailBitmap != null) {

                try {
                    CommonUtils.saveBitmap2Local(detailBitmap, cacheDir + "/" + UUID.randomUUID().toString() + ".jpg");
                    showErr("保存成功");

                    //通知文件夹扫描 保存的图片
                    Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                    Uri uri = Uri.fromFile(photoFile);
                    intent.setData(uri);
                    sendBroadcast(intent);

                } catch (IOException e) {
                    e.printStackTrace();
                    showErr("保存失败");
                }
            }

        }

    }

    /**
     * 是否取消语音发送, (只是用来改变界面效果, 不做最终决定权)
     */
    @Subscribe(threadMode = ThreadMode.MAIN) //在ui线程执行
    public void onDataSynEvent(Integer action) {
        switch (action) {

            case RecorderTextView.ACTION_DOWN://手指按下 弹出dialog

                //手指按下的时候  如果正在播放语音 则停止播放
                if (chatAdapter != null)
                    chatAdapter.stopPlayVideo();

                showDiago();

                speakTime = System.currentTimeMillis();//记录按下的时间
                mHandler.post(voiceRunnable);//监听话筒分贝
//                ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
//                scheduledExecutorService.scheduleAtFixedRate(voiceRunnable, 0, 300, TimeUnit.MILLISECONDS);
//                executorService.execute(voiceRunnable);//监听话筒分贝

                break;

            case RecorderTextView.ACTION_MOVE_SEND:
                tv_mind.setText(getResources().getString(R.string.slide_up_cancle_send));
                tv_mind.setBackgroundColor(getResources().getColor(R.color.transparent));
                break;

            case RecorderTextView.ACTION_MOVE_CANCLE://取消发送
                tv_mind.setText(getResources().getString(R.string.release_cancle_send));
                tv_mind.setBackgroundColor(getResources().getColor(R.color.red));
                break;

            case RecorderTextView.ACTION_UP://手指抬起,dialog消失
                Log.d(TAG, "--------------手指松开 up--------------");
                if (dialog != null && dialog.isShowing())
                    dialog.dismiss();
                break;

            case RecorderTextView.ACTION_UP_SHORT_TIME://录音时间过短
                Log.d(TAG, "--------------手指松开 时间太短 up--------------");
                tv_mind.setText(getResources().getString(R.string.speak_short));
                mHandler.post(dismissRunnable);
                break;

            case ChatView.LOAD_MORE_CHAT_HISTORY://获取更多的聊天记录
                //查找更多聊天记录
                //获取当前页面显示的条目
                startIndex = lists.size();
                executorService.execute(historyRunnable);
                break;

            case UPlayer.STOPPLAYING:
                Log.d(TAG, "设置为未播放状态");
                //改为停止播放状态
                chatAdapter.setIsPlaying(false);
                break;

        }

    }

    /**
     * 发送语音
     *
     * @param vb
     */
    @Subscribe(threadMode = ThreadMode.MAIN) //在ui线程执行
    public void onDataSynEvent(VideoBean vb) {

        if (contact == null) {
            showErr("好友信息异常");
            return;
        }

        if (!vb.isCancle) {
            if (send)
                //发送录音文件
                sendVideoRecord();
            else
                send = true;
        }

    }

    /**
     * 发送录音文件
     */
    private void sendVideoRecord() {

        if (TextUtils.isEmpty(MediaRecordManager.getInstance().getMediaPath())) {
            showErr("获取录音文件失败");
            return;
        }

//        if (!CommonUtils.isFriendOrGroupNum(sp, this, contact.channelId))//和对方不是好友,或者不是群成员,无法发送消息
//            return;

        //获取到发送的mb
        MessageBean mb = getSendMessageBean(MqttConstant.MQTTMESSAGEVOICE,
                MediaRecordManager.getInstance().getMediaPath(),
                Math.round(MediaPlayer.create(this, Uri.parse(MediaRecordManager.getInstance().getMediaPath())).getDuration() / 1000));

        sendMsg(mb);//发送聊天消息

    }

    /**
     * 收到了消息
     *
     * @param msb 消息msb对象
     */
    @Subscribe(threadMode = ThreadMode.MAIN) //在ui线程执行
    public void onDataSynEvent(MessageBean msb) {

        //如果收到topic不是该聊天的topic则不处理
        if (msb == null || contact == null || !contact.channelId.equals(msb.channelId))
            return;

//        if (MqttConstant.MQTTMESSAGENOTICE.equals(msb.messageType)) { //创建群, 增删群成员,修改群昵称
//            tbv.setTitle(msb.receiveName);//设置群昵称
//            updateChatList(msb); //更新界面
//            return;
//        }

        switch (msb.operationStyle) {

            case MqttConstant.RECEIVE_MESSAGE: //接受到了新消息
                //是自己发送的消息
                if (sp.getString(MqttConstant.USERID, "").equals(msb.sendId)) {

                    if (lists != null) {//遍历当前的消息,把发送状态修改为已送达 TODO

                        for (int i = 0; i < lists.size(); i++) {
                            if (lists.get(i).sendDate == msb.sendDate) {
                                lists.get(i).isReach = 0;//发送状态修改为已接受
                                break;
                            }
                        }
//                        return;
                    }
                }

                updateChatList(msb);//更新界面

                break;

            case MqttConstant.DELETE_RECENT_HISTORY://删除聊天记录

                if (lists != null && chatAdapter != null) {
                    lists.clear();
                    chatAdapter.notifyDataSetChanged();
                }

                break;

            case MqttConstant.OFF_GROUP://退出群
                finish();
                break;

        }

    }

    /**
     * 更新界面
     *
     * @param msb
     */
    private void updateChatList(MessageBean msb) {

        if (contact != null && contact.channelId.equals(msb.channelId)) {

//            if (!CommonUtils.isGroupChat(contact.channelId))
//                tbv.setTitle(msb.sendName);//私聊的话设置对方的昵称, 防止对方改名

            if (!msb.sendId.equals(sp.getString(MqttConstant.USERID, "")))
                lists.add(msb);
            chatAdapter.notifyDataSetChanged();

//            LogUtil.e("tag", " 是否需要滑动到最下面 : " + isScrollBottom());

            if (isScrollBottom()) {//如果不在底部 则不滑动到底部
                lv_contents.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
                lv_contents.setSelection(lv_contents.getCount());
            } else {
                lv_contents.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_DISABLED);
            }

        }
    }


    /**
     * 添加表情
     *
     * @param emo
     */
    @Subscribe(threadMode = ThreadMode.MAIN) //在ui线程执行
    public void onDataSynEvent(SpannableString emo) {

        int selectionStart = et_sendmessage.getSelectionStart();// 获取光标的位置

        if (MqttConstant.DELETEEMO.equals(emo.toString())) {

            //删除表情
            if (selectionStart > 0) {
                String body = et_sendmessage.getText().toString();
                if (!TextUtils.isEmpty(body)) {

                    String tempStr = body.substring(0, selectionStart);//截取出0到光标选中的一段内容
                    int i = tempStr.lastIndexOf("[");// 获取最后一个表情的位置
                    if (i != -1) {

                        CharSequence cs = tempStr.subSequence(i, selectionStart);//获取到 类似表情 格式的 字符串
                        if (mapplication.getEmoMap().containsKey(cs)) {//判断是否是一个表情

                            et_sendmessage.getEditableText().delete(i, selectionStart);
                        }
                    }

                }
            }

        } else {
            //指定光标处插入表情
            et_sendmessage.getEditableText().insert(selectionStart, emo);
        }

    }

    /**
     * 发送图片(拍照的)
     *
     * @param photoUrl
     */
    @Subscribe(threadMode = ThreadMode.ASYNC) //在ui线程执行
    public void onDataSynEvent(String photoUrl) {

        if (!TextUtils.isEmpty(photoUrl)) {

            Bitmap bitmap = CommonUtils.compressImageFromFile(photoUrl);
            final String photoUrl_m = getHintFile() + "/" + UUID.randomUUID().toString();

            try {

                CommonUtils.saveBitmap2Local(bitmap, photoUrl_m);

//                if (!CommonUtils.isFriendOrGroupNum(sp, this, contact.channelId))//和对方不是好友,或者不是群成员,无法发送消息
//                    return;

                //获取到发送的mb
                final MessageBean mb = getSendMessageBean(MqttConstant.MQTTMESSAGEPHOTO, photoUrl_m, 0);

                //获取发送的图片的七牛地址
                getSendPic(CommonUtils.compressByte(bitmap), mb);

            } catch (IOException e) {
                e.printStackTrace();
                showErr("发送失败");
            } finally {
                if (bitmap != null) {
                    bitmap.recycle();
                }
            }

        }

    }

    /**
     * 查看图片详情
     */
    public void showPicDetail(String photoUrl) {
        this.showingPhotoUrl = photoUrl;
        detailBitmap = BitmapFactory.decodeFile(photoUrl);
        pv_pre.setImageBitmap(detailBitmap);
        rl_pre.setVisibility(View.VISIBLE);
        isShowingPicDetail = true;
        mAttacher = new PhotoViewAttacher(pv_pre);
    }

    /**
     * 隐藏详情图片
     */
    public void hintPicDetail() {
        isShowingPicDetail = false;
        rl_pre.setVisibility(View.GONE);
        mAttacher = null;
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();

        if (isShowingPicDetail) {
            hintPicDetail();
            return;
        }

        //返回的时候 直接回到消息界面
        nextActivity(HomeActivity.class);

    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {

            case R.id.tv_save://保存图片
                savePic2Local();
                break;

            case R.id.tv_send://发送聊天消息
                sendChatMessage();
                break;

            case R.id.iv_audio://切换语音聊天模式
                changeVoiceStyle();
                break;

            case R.id.iv_emotion://表情

                //更换滚动模式
                lv_contents.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
                changeEmoStyle();

                break;

            case R.id.iv_add://添加图片,拍照,代办等

                //更换滚动模式
                lv_contents.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
                changePicStyle();

                break;

        }

    }

    /**
     * 切换拍照 选择图片的模式
     */
    private void changePicStyle() {
        //变成输入框模式
        if (isTalk) {
            et_sendmessage.setVisibility(View.VISIBLE);
            tv_rcd.setVisibility(View.GONE);
            isTalk = false;
        }

        iv_audio.setImageResource(R.mipmap.ic_voice);

        rl_emo.setVisibility(View.GONE); //把表情的布局隐藏掉
        isShowEmo = false;

        //布局显示中, 隐藏布局,布局隐藏中, 显示布局
        gv_photo.setVisibility(isShowPhoto ? View.GONE : View.VISIBLE);

        isShowPhoto = !isShowPhoto;
    }

    /**
     * 切换表情布局
     */
    private void changeEmoStyle() {
        //把发送图片的布局隐藏
        gv_photo.setVisibility(View.GONE);
        isShowPhoto = false;

        iv_audio.setImageResource(R.mipmap.ic_voice);

        //变成输入框模式
        if (isTalk) {
            et_sendmessage.setVisibility(View.VISIBLE);
            tv_rcd.setVisibility(View.GONE);
            isTalk = false;
        }

        if (isShowEmo) //隐藏表情viewpager
            rl_emo.setVisibility(View.GONE);
        else {
            //显示表情viewpager
            rl_emo.setVisibility(View.VISIBLE);
            EmoAdapter emoAdapter = new EmoAdapter(this);
            vp_emotion.setAdapter(emoAdapter);
            et_sendmessage.requestFocus();
            et_sendmessage.setFocusable(true);
            setPoint(0);
        }
        isShowEmo = !isShowEmo;
    }

    /**
     * 切换聊天模式
     */
    private void changeVoiceStyle() {

        et_sendmessage.setVisibility(isTalk ? View.VISIBLE : View.GONE);
        tv_rcd.setVisibility(isTalk ? View.GONE : View.VISIBLE);

        //把图标变成键盘样式或者语音样式
        iv_audio.setImageResource(isTalk ? R.mipmap.ic_voice : R.mipmap.ic_keybord);

        if (isTalk) {
            et_sendmessage.setFocusable(true);
            et_sendmessage.requestFocus();
            InputMethodManager inputManager =
                    (InputMethodManager) et_sendmessage.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            inputManager.showSoftInput(et_sendmessage, 0);
        }

        isTalk = !isTalk;

    }

    /**
     * 弹出语音框
     */
    private void showDiago() {

        if (dialog == null) {

            dialog = new Dialog(this, R.style.no_title);
            dialog.setCancelable(false);
            dialog.setCanceledOnTouchOutside(false);
            dialog.show();
            dialog.setContentView(R.layout.dialog_chat_speak);

            dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                @Override
                public void onDismiss(DialogInterface dialog) {
                    tv_rcd.setText(getResources().getString(R.string.press_speak));
                }
            });

            iv_voice = (ImageView) dialog.findViewById(R.id.iv_voice);
            tv_mind = (TextView) dialog.findViewById(R.id.tv_mind);
        } else {
            dialog.show();
        }
    }

    private MyHandler mHandler = new MyHandler(this);
//    private ScheduledExecutorService scheduledExecutor;

    private class MyHandler extends Handler {
        private final WeakReference<ChatActivity> mActivity;

        MyHandler(ChatActivity activity) {
            mActivity = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            ChatActivity activity = mActivity.get();
            if (activity != null) {

                switch (msg.what) {

                    case MDEIAVOICE://录音音量
                        //更新麦克风录音大小状态
                        updateVoiceStatus((int) msg.obj);
//                        scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
//                        scheduledExecutor.scheduleAtFixedRate(voiceRunnable, 300, 300, TimeUnit.MILLISECONDS);// 间隔取样时间 300毫秒
                        this.postDelayed(voiceRunnable, 300);// 间隔取样时间 300毫秒

                        long second = (System.currentTimeMillis() - speakTime) / 1000;

                        Log.d(TAG, " 当前说了 : " + second + "秒");

                        if (second >= 50) {//大于了50秒 TODO

                            if (second >= 60) {// 大于60秒 停止录音 发送录音文件, popup消失

                                MediaRecordManager.getInstance().stopRecordAndFile();

                                sendVideoRecord();
                                send = false;

                                if (dialog != null && dialog.isShowing())
                                    dialog.dismiss();

                                tv_rcd.setText(getResources().getString(R.string.press_speak));
                            }
                        }

                        break;

                    case QUERYHISTORY://查询聊天记录

                        List<MessageBean> historyByTopic = (List<MessageBean>) msg.obj;
//                        Log.d(TAG, "查询到的聊天记录数:" + historyByTopic.size());
                        if (historyByTopic.size() > 0) {

                            lists.addAll(0, historyByTopic);
                            chatAdapter.notifyDataSetChanged();
                            if (startIndex == 0) {
                                //第一次进入聊天页面时 查询聊天记录
                                lv_contents.setSelection(lv_contents.getCount());
                            } else { //向上翻页时,加载更多聊天记录
                                //更换滚动模式
                                lv_contents.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_DISABLED);
                                lv_contents.setSelection(historyByTopic.size() - 1);
                                lv_contents.smoothScrollBy(100, 1000);
                            }
                        }
                        break;
                }

            } else {
                //如果外部类
                mHandler = null;
            }
        }
    }


    /**
     * 更新麦克风音量变化
     * 更新话筒状态 分贝是也就是相对响度 分贝的计算公式K=20lg(Vo/Vi) Vo当前振幅值 Vi基准值为600：
     * 怎么制定基准值的呢？ 当20* Math.log10(mMediaRecorder.getMaxAmplitude() / Vi)==0的时候vi就是我所需要的基准值
     * 当我不对着麦克风说任何话的时候，测试获得的mMediaRecorder.getMaxAmplitude()值即为基准值。
     * Log.i("mic_", "麦克风的基准值：" + mMediaRecorder.getMaxAmplitude());前提时不对麦克风说任何话
     */
    private void updateVoiceStatus(int voice) {

        int ratio = voice / 50;//Vi基准值50
        int db = 0;// 分贝

        if (ratio > 1)
            db = (int) (20 * Math.log10(ratio));
//        LogUtil.e("tag", "分贝值：" + db + "     " + Math.log10(ratio));
        switch (db / 9) {

            case 0:
                iv_voice.setImageResource(R.mipmap.ic_voice_1);
                break;

            case 1:
                iv_voice.setImageResource(R.mipmap.ic_voice_2);
                break;

            case 2:
                iv_voice.setImageResource(R.mipmap.ic_voice_3);
                break;

            case 3:
                iv_voice.setImageResource(R.mipmap.ic_voice_4);
                break;

            case 4:
                iv_voice.setImageResource(R.mipmap.ic_voice_5);
                break;

            case 5:
                iv_voice.setImageResource(R.mipmap.ic_voice_6);
                break;

            case 6:
                iv_voice.setImageResource(R.mipmap.ic_voice_7);
                break;

            default:
                break;
        }

    }

    //实时改变音量大小的runnable
    private Runnable voiceRunnable = new Runnable() {

        @Override
        public void run() {

            Log.d(TAG, "  改变音量大小的 runnable  " + Thread.currentThread().getName() + ",时间:" + new Date().getTime());
            if (MediaRecordManager.getInstance().mMediaRecorder == null)
                return;
            int maxAmplitude = MediaRecordManager.getInstance().mMediaRecorder.getMaxAmplitude();
            Message msg = Message.obtain();
            msg.what = MDEIAVOICE;
            msg.obj = maxAmplitude;
            mHandler.sendMessage(msg);

        }
    };

    //让progress消失的runnable
    private Runnable dismissRunnable = new Runnable() {

        @Override
        public void run() {

            if (dialog != null && dialog.isShowing())
                dialog.dismiss();

        }
    };

    /**
     * 拍照
     */
    public void takePhoto() {

        String cacheDir = Environment.getExternalStorageDirectory().getPath() + Constant.PHOTO_PATH;

        File photoFile = new File(cacheDir);
        //文件夹不存在就创建文件夹
        if (!photoFile.exists())
            photoFile.mkdirs();

        //创建存放图片的jpg文件
        takePhotoFile = new File(photoFile, UUID.randomUUID().toString() + ".jpg");

        mIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        mIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(takePhotoFile));
        startActivityForResult(mIntent, TAKE_PHOTO_CODE);
    }

    /**
     * 从相册选择照片
     */
    public void choosePhoto() {
        mIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        startActivityForResult(mIntent, CHOOSE_PHOTO_CHAT_CODE);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, final Intent data) {

        switch (requestCode) {

            case TAKE_PHOTO_CODE: //拍照返回的code

                //   跳到图片操作页面
                if (takePhotoFile != null && takePhotoFile.exists()) {
                    mIntent = new Intent(this, ShowPhotoActivity.class);
                    mIntent.putExtra("photoUrl", takePhotoFile.getPath());
                    startActivity(mIntent);

                    //通知文件夹扫描 保存的图片
                    Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                    Uri uri = Uri.fromFile(takePhotoFile);
                    intent.setData(uri);
                    sendBroadcast(intent);
                }

                break;

            case CHOOSE_PHOTO_CHAT_CODE://从相册中选择图片

                if (data == null)
                    return;

                Uri selectedImage = data.getData();
                String[] filePathColumn = {MediaStore.Images.Media.DATA};

                Cursor cursor = getContentResolver().query(selectedImage,
                        filePathColumn, null, null, null);
                cursor.moveToFirst();

                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                String picturePath = cursor.getString(columnIndex);//图片路径
                cursor.close();

                //压缩图片
                final Bitmap bitmap = CommonUtils.compressImageFromFile(picturePath);
                String hintPath = getHintFile() + "/" + UUID.randomUUID().toString() + ".jpg";
                try {

                    CommonUtils.saveBitmap2Local(bitmap, hintPath);

//                    if (!CommonUtils.isFriendOrGroupNum(sp, this, contact.channelId))//和对方不是好友,或者不是群成员,无法发送消息
//                        return;

                    //获取到发送的mb
                    final MessageBean mb = getSendMessageBean(MqttConstant.MQTTMESSAGEPHOTO, hintPath, 0);

                    getSendPic(CommonUtils.compressByte(bitmap), mb);

                } catch (IOException e) {
                    e.printStackTrace();
                    showErr("图片选择失败");
                } finally {

                    if (bitmap != null)
                        bitmap.recycle();

                }

                break;

        }
    }

    private void getSendPic(final byte[] bytes, final MessageBean mb) {
        //获取发送的图片的七牛地址
        JSONObject j = new JSONObject();
        j.put("token", getToken());
        RetrofitHttpUtil.getInstance().uploadQiNiuToken(new BaseNoTObserver<UploadBean>() {
            @Override
            public void onHandleSuccess(final UploadBean uploadBean) {

                mHandler.post(new Runnable() {
                    @Override
                    public void run() {

                        if (uploadBean.getCode() == 0)
                            upLoadPic(uploadBean, bytes, mb);//根据token上传图片
                        else showErr(uploadBean.getCode_msg());
                    }
                });

            }

            @Override
            public void onHandleError(String message) {
                showErr(message);
            }

            @Override
            public void onReLogin(String message) {
                showErr(message);
                hideLoading();
                nextActivityWithSingleTask(LoginActivity.class);
            }

            @Override
            public void onSubscribe(Disposable d) {

            }
        }, new RequestBean().setData(j.toString()));
    }

    /**
     * 上传图片
     */
    protected void upLoadPic(final UploadBean uploadBean, byte[] bytes, final MessageBean mb) {

        UploadManager uploadManager = new UploadManager();
        uploadManager.put(bytes, uploadBean.getPath(), uploadBean.getToken(),
                new UpCompletionHandler() {
                    @Override
                    public void complete(String s, ResponseInfo responseInfo, org.json.JSONObject jsonObject) {

                        if (responseInfo.isOK()) {

                            MessageBean msb;
                            msb = mb;
                            msb.qiniuPath = uploadBean.getDomain() + uploadBean.getPath();
                            sendMsg(msb);//发送聊天消息
                        } else
                            showErr("图片发送失败");

                    }

                }, null);

    }

    /**
     * 获取隐藏文件夹
     */
    private String getHintFile() {

        String cacheDirHint = Environment.getExternalStorageDirectory().getPath() + MqttConstant.PHOTO_PATH_HINT;
        File photoHint = new File(cacheDirHint);

        //创建隐藏文件夹
        if (!photoHint.exists()) {
            photoHint.mkdirs();

            //再创建 .nomedia 文件nomedia
            File noMedia = new File(cacheDirHint + ".nomedia");
            if (!noMedia.exists()) {
                try {
                    noMedia.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else noMedia = null;

        }
        return cacheDirHint;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

//        Log.d(TAG, " 手势 : " + ev.getAction() + "");
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {

            //获取到当前的焦点view
            View v = getCurrentFocus();

            //是否隐藏软键盘
            if (isShouldHideInput(v, ev)) {
                InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
                if (imm != null) {
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
//                    Log.d(TAG, "==== 隐藏了软键盘 ====");
                }
            }

            //是否隐藏表情viewpager 和 选择图片的布局
            if (isShowEmo) {
                if (isShouldHideEmo(ev, rl_emo)) {
                    rl_emo.setVisibility(View.GONE);
                    isShowEmo = false;
                }
            }

            if (isShowPhoto) {
                if (isShouldHideEmo(ev, gv_photo)) {
                    gv_photo.setVisibility(View.GONE);
                    isShowPhoto = false;
                }
            }

            return super.dispatchTouchEvent(ev);
        }

//        Log.d(TAG, "=== getWindow().superDispatchTouchEvent(ev) || onTouchEvent(ev) ===");

        // 必不可少，否则所有的组件都不会有TouchEvent了
        return getWindow().superDispatchTouchEvent(ev) || onTouchEvent(ev);

    }

    /**
     * 是否隐藏表情viewpager
     *
     * @param ev
     * @return
     */
    private boolean isShouldHideEmo(MotionEvent ev, View v) {
        //如果点击的是这三个位置,不做处理, 点击的是其他的部位,则要隐藏表情的viewpager
        return !(isPointInView(iv_emotion, ev.getX(), ev.getY()) || isPointInView(iv_add, ev.getX(), ev.getY())
                || isPointInView(v, ev.getX(), ev.getY()));
    }

    /**
     * 判断x,y 坐标是否在view的控件上
     *
     * @param v 控件view
     * @param x 点击的x轴 点
     * @param y 点击的y轴 点
     * @return true 在view内, false 不做view内
     */
    private boolean isPointInView(View v, float x, float y) {
        //获取到iv_add控件在界面的位置
        int[] xy = {0, 0};
        v.getLocationInWindow(xy);

        int left = xy[0];
        int top = xy[1];
        int bottom = top + v.getHeight();
        int right = left + v.getWidth();

        return x > left && x < right && y > top && y < bottom;
    }

    /**
     * 是否要隐藏软键盘
     *
     * @return false 不隐藏软键盘  true隐藏软键盘
     */
    private boolean isShouldHideInput(View v, MotionEvent event) {

        int[] sendLeftTop = {0, 0};
        tv_send.getLocationInWindow(sendLeftTop);
        int left2 = sendLeftTop[0];
        int top2 = sendLeftTop[1];
        int bottom2 = top2 + tv_send.getHeight();
        int right2 = left2 + tv_send.getWidth();

        if (event.getX() > left2 && event.getX() < right2
                && event.getY() > top2 && event.getY() < bottom2 && tv_send.getVisibility() == View.VISIBLE) {
            Log.d(TAG, " 点击的部位 在 send 按钮内 ");
            return false;
        }

        if (v != null && (v instanceof EditText)) {

            int[] leftTop = {0, 0};
            //获取输入框当前的location位置
            v.getLocationInWindow(leftTop);
            int left = leftTop[0];
            int top = leftTop[1];
            int bottom = top + v.getHeight();
            int right = left + v.getWidth();
            return !(event.getX() > left && event.getX() < right
                    && event.getY() > top && event.getY() < bottom);
        }

        return false;

    }

    /**
     * 判断listview是要拉到最底部
     *
     * @return true 滑动到最底部, false无需滑动
     */
    private boolean isScrollBottom() {

//        Log.d(TAG, "childCount : " + lists.size() + ", lastPosition : " + lastPosition);
        //如果下面有三个以下的消息条目,则滑动到底部,否则不动
        return lists.size() - lv_contents.getLastVisiblePosition() <= 3;

    }

    /**
     * 获取mb
     *
     * @return mb (adapter里面的mb)
     */
    private MessageBean getSendMessageBean(String messageStyele, String content, double voiceLength) {

        MessageBean mb = new MessageBean();
//        mb.chatType = currentChatType;//聊天类型 单聊 还是私聊

        mb.channelId = contact.channelId;//聊天的topic
        mb.receiveName = contact.receiveName;//聊天的名称, 单聊就为聊天对象的昵称, 群聊为群聊昵称
        mb.receiveId = contact.receiveId;//聊天对象的id
        mb.receivePic = contact.receivePic;//聊天对象的头像

        mb.messageType = messageStyele;//消息类型
//        mb.content = bytes;//图片和音频的字节流
        mb.content = content;//消息内容,文字为内容, 图片和音频为存储路径
        mb.voiceLength = voiceLength;//录音时长

        mb.sendId = sp.getString(MqttConstant.USERID, "");//发送者的id
        mb.sendName = sp.getString(Constant.NICKNAME, "");//发送者的昵称
        mb.sendPic = sp.getString(Constant.USER_IMG, "");//发送者的头像
        mb.sendDate = System.currentTimeMillis();
        mb.isReach = MqttConstant.MESSAGE_SENDING;//状态为发送中..
        return mb;
    }

    /**
     * 发送聊天mb
     *
     * @param mb
     */
    public void sendMsg(final MessageBean mb) {

        executorService.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    MqttManager.getInstance().setMessage(contact.channelId, mb);
                } catch (Exception e) {
                    LogUtil.e(TAG, "发送失败");
                    mb.isReach = MqttConstant.MESSAGE_SEND_FAIL;
                    if (MqttConstant.MQTTNOTCONNECT.equals(e.getMessage())) {
                        //服务器未连接, 此时消息没有插入数据库
                        MqttManager.getInstance().save2DataBase(mb, MqttConstant.MESSAGE_SEND_FAIL);
                    } else {
                        //发送失败 修改isreach为fail
                        DatabaseManager.getInstance().updateReachStatus(ChatActivity.this,
                                mb.sendDate, MqttConstant.MESSAGE_SEND_FAIL, sp.getString(MqttConstant.USERID, ""), mb.channelId);
//                        mb.isReach = MqttConstant.MESSAGE_SENDING;
                    }
                    e.printStackTrace();
                }
            }
        });

        addChatItem(mb);
        et_sendmessage.setText("");//输入框设为空
    }

    /**
     * 发送item添加到页面上显示
     *
     * @param mb
     */
    private void addChatItem(MessageBean mb) {
        if (lists != null)
            lists.add(mb);
        chatAdapter.notifyDataSetChanged();
        lv_contents.setSelection(lv_contents.getCount());
    }

}